package com.acme.bankapp.service.bank;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import com.acme.bankapp.domain.account.Account;
import com.acme.bankapp.domain.account.CheckingAccount;
import com.acme.bankapp.domain.account.SavingAccount;
import com.acme.bankapp.domain.bank.Bank;
import com.acme.bankapp.domain.client.Client;
import com.acme.bankapp.domain.client.Gender;
import com.acme.bankapp.domain.exceptions.BankException;
import com.acme.bankapp.domain.exceptions.ClientExistsException;

public class BankService {
	private static final String BANK_FILE_PATH = "bank.ser";
	private static int accountsNumber;
	
	public void addClient(Bank bank, Client client) throws ClientExistsException {
		for (Client oldClient : bank.getClients()) {
			if (client.getName().equals(oldClient.getName())) {
				throw new ClientExistsException("Клиент с именем " + client.getName() +
									" уже существует");
			}
		}
		bank.addClient(client);
		try {
			saveBank(bank);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public SavingAccount createSavingAccount(double amount) {
		return new SavingAccount(getAccountNextId(), amount);
	}
	
	public Client createClient(String name, Gender gender) {
		return new Client(name, gender);
	}
	
	public CheckingAccount createCheckingAccount(double amount, double overdraft) {
		return new CheckingAccount(getAccountNextId(), amount, overdraft);
	}
	
	public void addAccount(Client client, Account account) {
		client.setAccount(account);
	}
	
	public Bank createBank() {
		return new Bank();
	}
	
	public void printMaximumAmountToWithdraw(Bank bank) {
		for (Client client : bank.getClients()) {
			if (client.getAccount() != null) {
				System.out.println("Maximum amount to withdraw for " + client.getName());
				System.out.println(client.getAccount().maximumAmountToWithdraw());				
			}
		}
	}
	
	private static int getAccountNextId() {
		return accountsNumber++;
	}
	
	public void saveBank(Bank bank) throws IOException {
		FileOutputStream fos = null;
		BufferedOutputStream bos = null;
		ObjectOutputStream oos = null;
		try {
			fos = new FileOutputStream(BANK_FILE_PATH);
			bos = new BufferedOutputStream(fos);
			oos = new ObjectOutputStream(bos);
			oos.writeObject(bank);
		} catch (IOException e) {
			throw e;
		} finally {
			if (oos != null) {
				try {
					oos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	public Bank readBank(String bankFilePath) throws BankException {
		Bank bank = null;
		FileInputStream fis = null;
		BufferedInputStream bis = null;
		ObjectInputStream ois = null;
		try {
			fis = new FileInputStream(bankFilePath);
			bis = new BufferedInputStream(fis);
			ois = new ObjectInputStream(bis);
			bank = (Bank) ois.readObject();
		} catch (IOException e) {
			throw new BankException("Cannot read bank from file", e);
		} catch (ClassNotFoundException e) {
			throw new BankException("Cannot read bank from file", e);
		} finally {
			if (ois != null) {
				try {
					ois.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return bank;
	}
}
